package com.kun.companion.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.kun.companion.core.config.LogbackConfiguration;
import com.kun.companion.core.constant.ComConstant;
import com.kun.companion.core.context.ContextService;
import com.kun.companion.core.ui.alert.ConfirmDialog;
import com.kun.companion.core.util.ComUtil;
import javafx.application.Application;
import javafx.application.HostServices;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.List;
import java.util.function.Function;

/**
 * JavaFX应用程序抽象基类，封装通用启动流程和上下文管理
 * <p>子类需实现加载包路径、主界面启动逻辑，并可通过重写钩子方法扩展初始化/销毁行为</p>
 *
 * @author gzc
 * @since 2025/1/26
 */
public abstract class AbstractApplication extends Application {
    private static final Logger log = LoggerFactory.getLogger(AbstractApplication.class);

    /**
     * 应用程序主窗口实例
     */
    protected static Stage APP_STAGE;

    /**
     * 启动后延迟回调时间（单位：毫秒）
     */
    protected static int startupBeforeCallbackTimed = 1000;

    /**
     * 类加载相关配置
     */
    protected static Class<? extends AbstractApplication> loader;
    protected static String[] args;

    protected static HostServices hostServices;
    public static HostServices obtainHostServices() {
        return hostServices;
    }
    /**
     * 资源加载函数，用于定位FXML等资源文件
     */
    protected static Function<String, URL> loadUrlFunction;

    /**
     * 应用程序图标
     */
    protected static Image iconImage;

    /**
     * 关闭确认对话框实例
     */
    protected static ConfirmDialog confirmDialog;

    /**
     * 正在运行的任务列表容器
     */
    public static VBox runningProgramListBox;

    /**
     * 基础包扫描路径列表（框架默认+子类扩展）
     */
    protected static final List<String> BASE_PACKAGE_LIST = ListUtil.list(false, ComConstant.FRAMEWORK_BASE_PACKAGE_PATH);

    /**
     * 获取应用程序主窗口
     *
     * @return 主舞台实例
     */
    public static Stage getAppStage() {
        return AbstractApplication.APP_STAGE;
    }

    /**
     * 设置主窗口实例（仅限内部使用）
     */
    private void setAppStage(Stage stage) {
        AbstractApplication.APP_STAGE = stage;
    }

    /**
     * 创建应用程序主窗口，子类可重写此方法实现自定义Stage
     *
     * @return 新创建的Stage实例
     */
    protected Stage createAppStage() {
        return new Stage();
    }

    /**
     * 获取当前应用加载器类
     */
    public static Class<? extends AbstractApplication> getLoader() {
        return AbstractApplication.loader;
    }

    /**
     * 创建应用程序图标，默认返回null需子类重写
     *
     * @return 图标Image对象或null
     */
    protected Image createIcon() {
        return null;
    }

    /**
     * 设置全局图标
     */
    private void setIcon(Image iconImage) {
        AbstractApplication.iconImage = iconImage;
    }

    /**
     * 获取当前应用程序图标
     */
    public static Image getIcon() {
        return AbstractApplication.iconImage;
    }

    /**
     * 更新正在运行的任务列表
     *
     * @param runningProgramNameLabel 要添加/移除的任务标签
     */
//    public static void updateRunningProgramList(Label runningProgramNameLabel) {
//        synchronized (runningProgramNameLabel) {
//            ObservableList<Node> observableList = AbstractApplication.runningProgramListBox.getChildren();
//            if (observableList.contains(runningProgramNameLabel)) {
//                System.out.println("删除 -> " + runningProgramNameLabel);
//                ComUtil.uiThreadRun(() -> observableList.remove(runningProgramNameLabel));
//            } else {
//                System.out.println("新增 -> " + runningProgramNameLabel);
//                ComUtil.uiThreadRun(() -> observableList.add(runningProgramNameLabel));
//            }
//        }
//    }
    public static void updateRunningProgramList(Label runningProgramNameLabel) {
        ComUtil.uiThreadRun(() -> {
            synchronized (AbstractApplication.runningProgramListBox.getChildren()) {
                ObservableList<Node> observableList = AbstractApplication.runningProgramListBox.getChildren();
                if (observableList.contains(runningProgramNameLabel)) {
                    observableList.remove(runningProgramNameLabel);
                } else {
                    observableList.add(runningProgramNameLabel);
                }
            }
        });
    }


    /**
     * 加载子类定义的包扫描路径
     *
     * @return 需要扫描的包路径数组
     */
    protected abstract String[] loadPackages();

    /**
     * 启动应用程序入口
     *
     * @param cls             主入口类（需继承AbstractApplication）
     * @param args            命令行参数
     * @param loadUrlFunction 资源加载函数
     * @throws Exception 启动失败时抛出异常
     */
    public static void run(Class<? extends AbstractApplication> cls,
                           String[] args,
                           Function<String, URL> loadUrlFunction) throws Exception {
        // 初始化日志配置
        LogbackConfiguration.configure();
        AbstractApplication.loader = cls;
        AbstractApplication.args = args;
        AbstractApplication.loadUrlFunction = loadUrlFunction;
        launch(cls, args);
    }

    /**
     * 初始化扩展点（子类可重写）
     *
     * @throws Exception 初始化异常
     */
    protected void doInit() throws Exception {
        // 默认空实现
    }

    /**
     * 主启动逻辑（子类必须实现）
     *
     * @param primaryStage 主窗口实例
     * @throws Exception 启动异常
     */
    protected abstract void doStart(Stage primaryStage) throws Exception;

    /**
     * 启动后回调扩展点（子类可重写）
     *
     * @throws Exception 回调执行异常
     */
    protected void doStartupBefore() throws Exception {
        // 默认空实现
    }

    /**
     * 停止应用程序扩展点（子类可重写）
     *
     * @throws Exception 停止过程异常
     */
    protected void doStop() throws Exception {
        // 默认空实现
    }

    /**
     * 初始化应用程序上下文
     *
     * @throws Exception 上下文加载异常
     */
    @Override
    public final void init() throws Exception {
        hostServices = getHostServices();
        // 合并包扫描路径
        AbstractApplication.BASE_PACKAGE_LIST.addAll(List.of(loadPackages()));

        // 初始化IoC容器
        ContextService.load(BASE_PACKAGE_LIST, loader, args, loadUrlFunction);

        log.info("开始执行初始化程序回调函数...");
        doInit();
        log.info("初始化程序回调函数执行完毕");
    }

    /**
     * JavaFX主启动入口
     *
     * @param primaryStage 主窗口实例
     */
    @Override
    public final void start(Stage primaryStage) throws Exception {
        log.info("应用程序启动中...");

        // 初始化关闭确认对话框
        confirmDialog = createCloseConfirmDialog();
        runningProgramListBox = createRunningProgramListBox();
        confirmDialog.setCenter(runningProgramListBox);

        // 初始化主窗口
        Stage stage = createAppStage();
        setAppStage(stage != null ? stage : primaryStage);
        Stage appStage = getAppStage();

        // 设置窗口图标
        setIcon(createIcon());
        Image icon = getIcon();
        if (icon != null) {
            appStage.getIcons().add(icon);
        }

        // 执行子类启动逻辑
        doStart(appStage);
        log.info("应用程序启动完成");

        // 注册窗口关闭事件
        appStage.setOnCloseRequest(event -> {
            if (!confirmDirectClose()) {
                event.consume(); // 阻止默认关闭
                if (showCloseConfirmation()) {
                    appStage.close();
                }
            }
        });
    }

    /**
     * 创建关闭确认对话框
     *
     * @return 预配置的确认对话框实例
     */
    protected ConfirmDialog createCloseConfirmDialog() {
        ConfirmDialog confirmDialog = new ConfirmDialog("关闭确认", APP_STAGE);
        confirmDialog.setTop(new Label("以下任务正在运行中，是否马上退出程序？"));
        return confirmDialog;
    }

    /**
     * 创建运行任务列表容器
     *
     * @return 垂直布局容器
     */
    protected VBox createRunningProgramListBox() {
        return new VBox();
    }

    /**
     * 判断是否允许直接关闭（无运行任务时可直接关闭）
     *
     * @return true-允许直接关闭，false-需要确认
     */
    protected boolean confirmDirectClose() {
        return CollUtil.isEmpty(runningProgramListBox.getChildren());
    }

    /**
     * 显示关闭确认对话框
     *
     * @return 用户是否确认关闭
     */
    private boolean showCloseConfirmation() {
        return confirmDialog.showAndWaitResult();
    }

    /**
     * 应用程序停止时清理资源
     */
    @Override
    public final void stop() throws Exception {
        log.info("执行停止回调...");
        doStop();
        ContextService.destroy();
        log.info("应用程序已完全停止");
    }
}